home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Audio, Video & Photo / Songbird 0.7.0 / Songbird_0.7.0_windows-i686-msvc8.exe / jsmodules / DOMUtils.jsm < prev    next >
Text File  |  2008-08-06  |  16KB  |  452 lines

  1. /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* vim: set sw=2 :miv */
  3. /*
  4. //
  5. // BEGIN SONGBIRD GPL
  6. //
  7. // This file is part of the Songbird web player.
  8. //
  9. // Copyright(c) 2005-2008 POTI, Inc.
  10. // http://songbirdnest.com
  11. //
  12. // This file may be licensed under the terms of of the
  13. // GNU General Public License Version 2 (the "GPL").
  14. //
  15. // Software distributed under the License is distributed
  16. // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
  17. // express or implied. See the GPL for the specific language
  18. // governing rights and limitations.
  19. //
  20. // You should have received a copy of the GPL along with this
  21. // program. If not, go to http://www.gnu.org/licenses/gpl.html
  22. // or write to the Free Software Foundation, Inc.,
  23. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  24. //
  25. // END SONGBIRD GPL
  26. //
  27. */
  28.  
  29. /**
  30.  * \file  DOMUtils.jsm
  31.  * \brief Javascript source for the DOM utility services.
  32.  */
  33.  
  34. //------------------------------------------------------------------------------
  35. //
  36. // DOM utility JSM configuration.
  37. //
  38. //------------------------------------------------------------------------------
  39.  
  40. EXPORTED_SYMBOLS = [ "DOMUtils", "DOMEventListenerSet" ];
  41.  
  42.  
  43. //------------------------------------------------------------------------------
  44. //
  45. // DOM utility defs.
  46. //
  47. //------------------------------------------------------------------------------
  48.  
  49. const Cc = Components.classes;
  50. const Ci = Components.interfaces;
  51. const Cr = Components.results
  52. const Cu = Components.utils
  53.  
  54.  
  55. //------------------------------------------------------------------------------
  56. //
  57. // DOM utility services.
  58. //
  59. //------------------------------------------------------------------------------
  60.  
  61. var DOMUtils = {
  62.   //----------------------------------------------------------------------------
  63.   //
  64.   // DOM utility services.
  65.   //
  66.   //----------------------------------------------------------------------------
  67.  
  68.   /**
  69.    * Load a document using the URI string specified by aDocumentURI and return
  70.    * it as an nsIDOMDocument.
  71.    *
  72.    * \param aDocumentURI        Document URI string.
  73.    *
  74.    * \return                    An nsIDOMDocument document.
  75.    */
  76.  
  77.   loadDocument: function DOMUtils_loadDocument(aDocumentURI) {
  78.     // Open the document.
  79.     var ioSvc = Cc["@mozilla.org/network/io-service;1"]
  80.                   .getService(Ci.nsIIOService);
  81.     var channel = ioSvc.newChannel(aDocumentURI, null, null);
  82.     var inputStream = channel.open();
  83.  
  84.     // Load and return the document.
  85.     var domParser = Cc["@mozilla.org/xmlextras/domparser;1"]
  86.                       .createInstance(Ci.nsIDOMParser);
  87.     return domParser.parseFromStream(inputStream,
  88.                                      null,
  89.                                      channel.contentLength,
  90.                                      "text/xml");
  91.   },
  92.  
  93.  
  94.   /**
  95.    *   Import the child elements of the parent element with the ID specified by
  96.    * aSrcParentID within the document specified by aSrcDocument.  Import them
  97.    * as child elements of the node specified by aDstNode.
  98.    *   For each imported child, set attributes as specified by the
  99.    * aChildAttrList object.  Use the name of each field in aChildAttrList as the
  100.    * name of an attribute, and set the attribute value to the field value.
  101.    *   Note that only child elements are imported.  Non-element child nodes such
  102.    * as text nodes are are not imported.  The descendents of all imported child
  103.    * elements are also imported, including non-element descendents.
  104.    *
  105.    * \param aDstNode            Destination node into which to import child
  106.    *                            elements.
  107.    * \param aSrcDocument        Document from which to import child elements.
  108.    * \param aSrcParentID        ID of parent node from which to import child
  109.    *                            elements.
  110.    * \param aChildAttrList      List of child attributes to set.
  111.    */
  112.  
  113.   importChildElements: function DOMUtils_importChildElements(aDstNode,
  114.                                                              aSrcDocument,
  115.                                                              aSrcParentID,
  116.                                                              aChildAttrList) {
  117.     // Get the destination document and the list of source children.
  118.     var dstDoc = aDstNode.ownerDocument;
  119.     var srcChildList = aSrcDocument.getElementById(aSrcParentID).childNodes;
  120.  
  121.     // Import the source elements.
  122.     for (var i = 0; i < srcChildList.length; i++) {
  123.       // Get the next source child.  Skip if not an element.
  124.       var srcChild = srcChildList[i];
  125.       if (srcChild.nodeType != Ci.nsIDOMNode.ELEMENT_NODE)
  126.         continue;
  127.  
  128.       // Import the source child into the destination document.
  129.       dstChild = dstDoc.importNode(srcChild, true);
  130.  
  131.       // Add the child to the destination node.
  132.       aDstNode.appendChild(dstChild);
  133.  
  134.       // Add the child attributes.
  135.       for (var attrName in aChildAttrList) {
  136.         dstChild.setAttribute(attrName, aChildAttrList[attrName]);
  137.       }
  138.     }
  139.   },
  140.  
  141.  
  142.   /**
  143.    * Copy the attributes specified by aAttributeList from the element specified
  144.    * by aSrcElem to the element specified by aDstElem.  If an attribute is not
  145.    * set in aSrcElem, do not change that attribute in aDstElem unless
  146.    * aRemoveAttributes is true; if aRemoveAttributes is true, remove the
  147.    * attribute from aDstElem.
  148.    *
  149.    * \param aSrcElem            Source element.
  150.    * \param aDstElem            Destination element.
  151.    * \param aAttributeList      Array of attribute names.
  152.    * \param aRemoveAttributes   Remove attributes from aDstElem that aren't set
  153.    *                            in aSrcElem.
  154.    */
  155.  
  156.   copyAttributes: function DOMUtils_copyAttributes(aSrcElem,
  157.                                                    aDstElem,
  158.                                                    aAttributeList,
  159.                                                    aRemoveAttributes) {
  160.     // Copy the attributes.
  161.     for (var i = 0; i < aAttributeList.length; i++) {
  162.       // Get attribute name.
  163.       var attribute = aAttributeList[i];
  164.  
  165.       // If source element does not have the attribute, do nothing or remove
  166.       // the attribute as specified.
  167.       if (!aSrcElem.hasAttribute(attribute)) {
  168.         if (aRemoveAttributes)
  169.           aDstElem.removeAttribute(attribute);
  170.         continue;
  171.       }
  172.  
  173.       // Copy the attribute from the source element to the destination if the
  174.       // attribute values differ.
  175.       var srcAttributeVal = aSrcElem.getAttribute(attribute);
  176.       var dstAttributeVal = aDstElem.getAttribute(attribute);
  177.       if (srcAttributeVal != dstAttributeVal)
  178.         aDstElem.setAttribute(attribute, srcAttributeVal);
  179.     }
  180.   },
  181.  
  182.  
  183.   /**
  184.    * Search the children of the element specified by aRootElem for elements
  185.    * with the attribute specified by aAttrName set to the value specified by
  186.    * aAttrValue.  Return an array containing all matching elements.
  187.    * If aAttrValue is not specified, return all elements with the specified
  188.    * attribute, regardless of value.
  189.    *
  190.    * \param aRootElem           Root element from which to start searching.
  191.    * \param aAttrName           Attribute name to search for.
  192.    * \param aAttrValue          Attribute value to search for.
  193.    *
  194.    * \return                    Array containing found elements.
  195.    */
  196.  
  197.   getElementsByAttribute: function DOMUtils_getElementsByAttribute(aRootElem,
  198.                                                                    aAttrName,
  199.                                                                    aAttrValue) {
  200.     // Start searching for elements from the root.
  201.     var matchList = [];
  202.     this._getElementsByAttribute(aRootElem, aAttrName, aAttrValue, matchList);
  203.  
  204.     return matchList;
  205.   },
  206.  
  207.   _getElementsByAttribute: function
  208.                              DOMUtils__getElementsByAttribute(aRootElem,
  209.                                                               aAttrName,
  210.                                                               aAttrValue,
  211.                                                               aMatchList) {
  212.     // Search each of the children.
  213.     var childList = aRootElem.childNodes;
  214.     for (var i = 0; i < childList.length; i++) {
  215.       // Check the child node for a match.
  216.       var child = childList[i];
  217.       if (child.hasAttributes() && child.hasAttribute(aAttrName)) {
  218.         if (!aAttrValue || (child.getAttribute(aAttrName) == aAttrValue))
  219.           aMatchList.push(child);
  220.       }
  221.  
  222.       // Check each of the child's children.
  223.       this._getElementsByAttribute(child, aAttrName, aAttrValue, aMatchList);
  224.     }
  225.   },
  226.  
  227.  
  228.   //----------------------------------------------------------------------------
  229.   //
  230.   // DOM node destruction services.
  231.   //
  232.   //   When a node is removed from a DOM tree, any XBL bindings bound to that
  233.   // node or its children are not detached.  Thus, the binding destructors are
  234.   // not called.  The XBL bindings are not detached until the owner document is
  235.   // destroyed.  This can lead to memory leaks if XBL bound nodes are
  236.   // dynamically added and removed from a document.
  237.   //   The DOM node destruction services provide support for releasing XBL
  238.   // binding resources before the XBL binding is detached.  An XBL binding may
  239.   // add a destroy function by calling addNodeDestroyFunc.  Multiple destroy
  240.   // functions may be added for an XBL binding (e.g., for extended bindings).
  241.   //   Before a node is removed from a document, destroyNode should be called.
  242.   // This function recursively calls the destroy functions for all of the nodes
  243.   // children, including the anonymous children.  Note that destroyNode must be
  244.   // called before node removal since node removal removes XBL binding content.
  245.   // If destroyNode is called after node removal, anonymous child nodes will not
  246.   // be destroyed.
  247.   //
  248.   //----------------------------------------------------------------------------
  249.  
  250.   /**
  251.    * Add the destroy function specified by aFunc to the list of destroy
  252.    * functions for the node specified by aNode.  The destroy function is only
  253.    * called once and is removed from the destroy function list when called.
  254.    *
  255.    * \param aNode               Node for which to add destroy function.
  256.    * \param aFunc               Destroy function.
  257.    */
  258.  
  259.   addNodeDestroyFunc: function DOMUtils_addNodeDestroyFunc(aNode,
  260.                                                            aFunc) {
  261.     // Ensure the destroy function list exists.
  262.     if (!aNode.destroyFuncList)
  263.       aNode.destroyFuncList = [];
  264.  
  265.     // Push the destroy function on the end of the list.
  266.     aNode.destroyFuncList.push(aFunc);
  267.   },
  268.  
  269.  
  270.   /**
  271.    * Recursively call the destroy functions for all child nodes, including
  272.    * anonymous nodes, for the node specified by aNode.
  273.    *
  274.    * \param aNode               Node to destroy.
  275.    */
  276.  
  277.   destroyNode: function DOMUtils_destroyNode(aNode) {
  278.     // Destroy all of the node's children, including the anonymous children.
  279.     var nodeDocument = aNode.ownerDocument;
  280.     this.destroyNodeList(nodeDocument.getAnonymousNodes(aNode));
  281.     this.destroyNodeList(aNode.childNodes);
  282.  
  283.     // Call the node destroy functions.
  284.     while (aNode.destroyFuncList) {
  285.       // Pop the next destroy function from the end of the list and call it.
  286.       var destroyFunc = aNode.destroyFuncList.pop();
  287.       destroyFunc();
  288.  
  289.       // If the destroy function list is empty, remove it.
  290.       if (!aNode.destroyFuncList.length)
  291.         aNode.destroyFuncList = null;
  292.     }
  293.   },
  294.  
  295.  
  296.   /**
  297.    * Destroy all nodes in the list specified by aNodeList.
  298.    *
  299.    * \param aNodeList           Array list of nodes to destroy.
  300.    */
  301.  
  302.   destroyNodeList: function DOMUtils_destroyNodeList(aNodeList) {
  303.     if (!aNodeList)
  304.       return;
  305.  
  306.     for (var i = 0; i < aNodeList.length; i++) {
  307.       this.destroyNode(aNodeList[i]);
  308.     }
  309.   }
  310. };
  311.  
  312.  
  313. //------------------------------------------------------------------------------
  314. //
  315. // DOM event listener set services.
  316. //
  317. //   These services may be used to maintain a set of DOM event listeners and to
  318. // facilitate the removal of DOM event listeners.
  319. //
  320. //------------------------------------------------------------------------------
  321.  
  322. /**
  323.  * Construct a DOM event listener set object.
  324.  */
  325.  
  326. function DOMEventListenerSet()
  327. {
  328.   // Initialize some fields.
  329.   this._eventListenerList = {};
  330. }
  331.  
  332. // Set constructor.
  333. DOMEventListenerSet.prototype.constructor = DOMEventListenerSet;
  334.  
  335. // Define the class.
  336. DOMEventListenerSet.prototype = {
  337.   //
  338.   // DOM event listener set fields.
  339.   //
  340.   //   _eventListenerList       List of event listeners.
  341.   //   _nextEventListenerID     Next event listener ID.
  342.   //
  343.  
  344.   _eventListenerList: null,
  345.   _nextEventListenerID: 0,
  346.  
  347.  
  348.   /**
  349.    * Add an event listener for the element specified by aElement with the
  350.    * parameters specified by aType, aListener, and aUseCapture.  If aOneShot is
  351.    * true, remove listener after it's called once.  Return an ID that may be
  352.    * used to reference the added listener.
  353.    *
  354.    * \param aElement            Element for which to add an event listener.
  355.    * \param aType               Type of event for which to listen.
  356.    * \param aListener           Listener function.
  357.    * \param aUseCapture         True if event capture should be used.
  358.    * \param aOneShot            True if listener is a one-shot listener.
  359.    *
  360.    * \return                    Event listener ID.
  361.    */
  362.  
  363.   add: function DOMEventListenerSet_add(aElement,
  364.                                         aType,
  365.                                         aListener,
  366.                                         aUseCapture,
  367.                                         aOneShot) {
  368.     // Create the event listener object.
  369.     var eventListener = {};
  370.     eventListener.id = this._nextEventListenerID++;
  371.     eventListener.element = aElement;
  372.     eventListener.type = aType;
  373.     eventListener.listener = aListener;
  374.     eventListener.useCapture = aUseCapture;
  375.     eventListener.oneShot = aOneShot;
  376.  
  377.     // Use one-shot function if listener is a one-shot listener.
  378.     var listenerFunc = eventListener.listener;
  379.     if (eventListener.oneShot) {
  380.       var _this = this;
  381.       listenerFunc =
  382.         function(aEvent) { return _this._doOneShot(aEvent, eventListener); };
  383.     }
  384.  
  385.     // Add the event listener.
  386.     eventListener.element.addEventListener(eventListener.type,
  387.                                            listenerFunc,
  388.                                            eventListener.useCapture);
  389.     this._eventListenerList[eventListener.id] = eventListener;
  390.  
  391.     return (eventListener.id);
  392.   },
  393.  
  394.  
  395.   /**
  396.    * Remove the event listener specified by aEventListenerID.
  397.    *
  398.    * \param aEventListenerID    ID of event listener to remove.
  399.    */
  400.  
  401.   remove: function DOMEventListenerSet_remove(aEventListenerID) {
  402.     // Get the event listener.  Do nothing if not found.
  403.     var eventListener = this._eventListenerList[aEventListenerID];
  404.     if (!eventListener)
  405.       return;
  406.  
  407.     // Remove the event listener.
  408.     eventListener.element.removeEventListener(eventListener.type,
  409.                                               eventListener.listener,
  410.                                               eventListener.useCapture);
  411.     delete this._eventListenerList[aEventListenerID];
  412.   },
  413.  
  414.  
  415.   /**
  416.    * Remove all event listeners.
  417.    */
  418.  
  419.   removeAll: function DOMEventListenerSet_removeAll() {
  420.     // Remove all event listeners.
  421.     for (var id in this._eventListenerList) {
  422.       this.remove(id);
  423.     }
  424.     this._eventListenerList = {};
  425.   },
  426.  
  427.  
  428.   //----------------------------------------------------------------------------
  429.   //
  430.   // Internal DOM event listener set services.
  431.   //
  432.   //----------------------------------------------------------------------------
  433.  
  434.   /**
  435.    * Dispatch the event specified by aEvent to the one-shot listener specified
  436.    * by aEventListener and remove the listener.
  437.    *
  438.    * \param aEvent              Event to dispatch.
  439.    * \param aEventListener      Event listener to which to dispatch event.
  440.    */
  441.  
  442.   _doOneShot: function DOMEventListenerSet__doOneShot(aEvent, aEventListener) {
  443.     // Remove event listener if one-shot.
  444.     if (aEventListener.oneShot)
  445.       this.remove(aEventListener.id);
  446.  
  447.     // Dispatch event to listener.
  448.     return aEventListener.listener(aEvent);
  449.   }
  450. };
  451.  
  452.